"""
@author: 江同学呀
@file: character_filter.py
@date: 2024/11/25 22:54
@desc:
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/analysis-charfilters.html
"""
from typing import Dict, List

from espc.err import ESPCInitError
from espc.orm.model.base.base import _Base


class _BaseCharacterFilter(_Base):
    """
    字符筛选器

    Character filters are used to preprocess the stream of characters before it is passed to the tokenizer.
    A character filter receives the original text as a stream of characters and can transform the stream by adding,
    removing, or changing characters. For instance, a character filter could be used to convert Hindu-Arabic numerals
    (٠‎١٢٣٤٥٦٧٨‎٩‎) into their Arabic-Latin equivalents (0123456789), or to strip HTML elements like <b> from the
    stream.
    Elasticsearch has a number of built in character filters which can be used to build custom analyzers.

    字符过滤器用于在将字符流传递给分词器之前对其进行预处理。
    字符筛选器将原始文本作为字符流接收，并可以通过添加、删除或更改字符来转换流。例如，字符过滤器可用于将印度-阿拉伯数字 （٠١٢٣٤٥٦٧٨٩） 转换为
    其阿拉伯-拉丁字母等价物 （0123456789），或从流中去除 <b> 等 HTML 元素。
    Elasticsearch 具有许多内置字符过滤器，可用于构建自定义分析器。
    """
    type: str

    def __init__(self, name: str, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.name: str = name
        return

    def _build(self) -> Dict:
        return {
            "type": self.type,
        }


class HTMLStripCharacterFilter(_BaseCharacterFilter):
    """
    HTML 条带字符过滤器
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/analysis-htmlstrip-charfilter.html

    Strips HTML elements from a text and replaces HTML entities with their decoded value (e.g, replaces &amp; with &).
    The html_strip filter uses Lucene’s HTMLStripCharFilter.
    从文本中去除 HTML 元素，并将 HTML 实体替换为其解码值（例如，将 & 替换为 &）。
    html_strip 筛选器使用 Lucene 的 HTMLStripCharFilter。

    :param escaped_tags:
        (Optional, array of strings) Array of HTML elements without enclosing angle brackets (< >). The filter skips
        these HTML elements when stripping HTML from the text. For example, a value of [ "p" ] skips the <p> HTML
        element.
        （可选，字符串数组）不带尖括号的 HTML 元素数组 （< >）。从文本中去除 HTML 时，过滤器会跳过这些 HTML 元素。例如，值 [ “p” ]
        会跳过 <p> HTML 元素。
    """
    type: str = "html_strip"

    def __init__(self, name: str, escaped_tags: List[str] = None, *args, **kwargs):
        super().__init__(name, *args, **kwargs)
        self._escaped_tags: List[str] = escaped_tags
        return

    def _build(self) -> Dict:
        body: Dict = super()._build()
        if self._escaped_tags:
            body["escaped_tags"] = self._escaped_tags
        return body


class MappingCharacterFilter(_BaseCharacterFilter):
    """
    映射字符过滤器
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/analysis-mapping-charfilter.html

    The mapping character filter accepts a map of keys and values. Whenever it encounters a string of characters that
    is the same as a key, it replaces them with the value associated with that key.
    Matching is greedy; the longest pattern matching at a given point wins. Replacements are allowed to be the empty
    string.
    The mapping filter uses Lucene’s MappingCharFilter.
    映射字符筛选器接受键和值的映射。每当遇到与键相同的字符串时，它都会将它们替换为与该键关联的值。
    匹配是贪婪的;在给定点匹配时间最长的模式获胜。替换项可以是空字符串。
    映射筛选器使用 Lucene 的 MappingCharFilter。

    :param mappings:
        (Required*, array of strings) Array of mappings, with each element having the form key => value.
        Either this or the mappings_path parameter must be specified.
        （必需*，字符串数组）映射数组，每个元素都具有 form key => 值。
        必须指定 this 或 mappings_path 参数。
    :param mappings_path:
        (Required*, string) Path to a file containing key => value mappings.
        This path must be absolute or relative to the config location, and the file must be UTF-8 encoded. Each
        mapping in the file must be separated by a line break.
        Either this or the mappings parameter must be specified.
        （必需*，字符串）包含键 => 值映射的文件的路径。
        此路径必须是绝对路径或相对于配置位置，并且文件必须采用 UTF-8 编码。文件中的每个映射都必须用换行符分隔。
        必须指定 this 或 mappings 参数。
    """
    type: str = "mapping"

    def __init__(self, name: str, mappings: List[str] = None, mappings_path: str = None, *args, **kwargs):
        if not mappings and not mappings_path:
            raise ESPCInitError("mappings 或 mappings_path 必须有一个被定义。")
        super().__init__(name, *args, **kwargs)
        self._mappings: List[str] = mappings
        self._mappings_path: str = mappings_path
        return

    def _build(self) -> Dict:
        body: Dict = super()._build()
        if self._mappings:
            body["mappings"] = self._mappings
        if self._mappings_path:
            body["mappings_path"] = self._mappings_path
        return body


class PatternReplaceCharacterFilter(_BaseCharacterFilter):
    """
    模式替换字符过滤器
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/analysis-pattern-replace-charfilter.html

    The pattern_replace character filter uses a regular expression to match characters which should be replaced with
    the specified replacement string. The replacement string can refer to capture groups in the regular expression.
    pattern_replace 字符过滤器使用正则表达式来匹配应替换为指定替换字符串的字符。替换字符串可以引用正则表达式中的捕获组。

    :param pattern:
        A Java regular expression. Required.
        Java 正则表达式。必填。
    :param replacement:
        The replacement string, which can reference capture groups using the $1..$9 syntax, as explained here.
        替换字符串，可以使用 $1..$9 语法，如此处所述。
    :param flags:
        Java regular expression flags. Flags should be pipe-separated, eg "CASE_INSENSITIVE|COMMENTS".
        Java 正则表达式标志。标志应以管道分隔，例如 “CASE_INSENSITIVE|评论”。
    """
    type: str = "pattern_replace"

    def __init__(self, name: str, pattern: str, replacement: str = None, flags: str = None, *args, **kwargs):
        super().__init__(name, *args, **kwargs)
        self._pattern: str = pattern
        self._replacement: str = replacement
        self._flags: str = flags
        return

    def _build(self) -> Dict:
        body: Dict = super()._build()
        if self._pattern:
            body["pattern"] = self._pattern
        if self._replacement:
            body["replacement"] = self._replacement
        if self._flags:
            body["flags"] = self._flags
        return body









